package com.easylinkin.linkappapi.config.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.config.constant.ConfigConstant;
import com.easylinkin.linkappapi.config.dao.ConfigMapper;
import com.easylinkin.linkappapi.config.entity.Config;
import com.easylinkin.linkappapi.config.entity.vo.ConfigVo;
import com.easylinkin.linkappapi.config.service.ConfigService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Config表服务实现类
 *
 * @author CodeGenerator
 * @date 2022/07/20
 */
@Slf4j
@Service("appConfigService")
public class ConfigServiceImpl extends ServiceImpl
        <ConfigMapper, Config> implements ConfigService {
    @Resource
    private CommonService commonService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Override
    public boolean saveOne(Config appConfig) {
        commonService.setCreateAndModifyInfo(appConfig);
        appConfig.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validParamRequired(appConfig);
        validRepeat(appConfig);
        validParamFormat(appConfig);
        return save(appConfig);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBatch2(List<Config> configList) {
        for (Config config : configList) {
            saveOne(config);
        }
    }

    @Override
    public void copyLastConfigToNewTenant(LinkappTenant oldLinkappTenant, LinkappTenant linkappTenant) {
        if (oldLinkappTenant != null && StringUtils.isNotBlank(oldLinkappTenant.getId()) && linkappTenant != null && StringUtils.isNotBlank(linkappTenant.getId())) {
            //查询配置
            Config exampleConfig = new Config();
            exampleConfig.setTenantId(oldLinkappTenant.getId());
            List<Config> oldTenantConfigLs = this.baseMapper.selectList2(exampleConfig);

            if (CollectionUtil.isNotEmpty(oldTenantConfigLs)) {
                //插入新租户配置
                oldTenantConfigLs.stream().forEach(c -> {
                    Config inConfig = new Config();
                    BeanUtil.copyProperties(c, inConfig, "id,tenantId,createTime,modifyTime");
                    inConfig.setTenantId(linkappTenant.getId());
                    inConfig.setCreateTime(DateUtil.date());
                    inConfig.setModifyTime(inConfig.getCreateTime());
                    inConfig.setValue(getCoveredRightTenantIdValue(linkappTenant.getId(), inConfig.getValue()));
                    this.baseMapper.insert(inConfig);
                });
            }
        } else {
            log.warn("不执行复制租户配置，原租户或新租户为空");
        }
    }

    private static String getCoveredRightTenantIdValue(@Length(max = 32, message = "id 超长") String tenantId, String value) {
        try {
            if (JSONObject.isValidObject(value)) {
                JSONObject jsonObject = JSONObject.parseObject(value);
                if (jsonObject.get("tenantId") != null) {
                    jsonObject.put("tenantId", tenantId);
                }
                return jsonObject.toJSONString();
            } else if (JSONObject.isValidArray(value)) {
                List<JSONObject> array = JSONArray.parseArray(value, JSONObject.class);
                for (JSONObject jsonObject : array) {
                    if (jsonObject.get("tenantId") != null) {
                        jsonObject.put("tenantId", tenantId);
                    }
                }
                return array.toString();
            }
        } catch (Exception e) {
            log.error("解析json失败", e);
        }
        return value;
    }

    public static void main(String[] args) {
        String value = "[{\"tenantId\":\"333\",\"deviceCodes\":[\"40194860\",\"VIR20220728\"],\"attrs\":[\"pm10\",\"pm25\"]},{\"tenantId\":\"4456\",\"deviceCodes\":[\"40194860\",\"VIR20220728\"],\"attrs\":[\"pm10\",\"pm25\"]}]\n";
        String value2 = "{\"tenantId\":\"dabdbe8e81d00e14d0eb52c4d35d37c6\",\"attrs\":[\"pm10\",\"pm25\"],\"deviceCodes\":[\"40194860\",\"VIR20220728\"]}";
        String value3 = "tenantId\":\"dabdbe8e81d00e14d0eb52c4d35d37c6\",";
        String value4 = "tenantId,123,456";
        System.out.println(getCoveredRightTenantIdValue("66666",value));
        System.out.println(getCoveredRightTenantIdValue("66666",value2));
        System.out.println(getCoveredRightTenantIdValue("66666",value3));
        System.out.println(getCoveredRightTenantIdValue("66666",value4));
    }

    @Override
    public Config getOneByKey(String key) {
        Config exampleConfig = new Config();
        exampleConfig.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        exampleConfig.setKey(key);
        List<Config> oldTenantConfigLs = this.baseMapper.selectList2(exampleConfig);
        if(CollectionUtil.isNotEmpty(oldTenantConfigLs)){
            return oldTenantConfigLs.get(0);
        }
        //如果没有查到，则查全局
        exampleConfig.setTenantId(null);
        oldTenantConfigLs = this.baseMapper.selectList2(exampleConfig);
        if(CollectionUtil.isNotEmpty(oldTenantConfigLs)){
            return oldTenantConfigLs.get(0);
        }
        return null;
    }

    @Override
    public Config getOneByKeyAndTenantId(String key, String tenantId) {
        Config exampleConfig = new Config();
        exampleConfig.setTenantId(tenantId);
        exampleConfig.setKey(key);
        List<Config> oldTenantConfigLs = this.baseMapper.selectList2(exampleConfig);
        if(CollectionUtil.isNotEmpty(oldTenantConfigLs)){
            return oldTenantConfigLs.get(0);
        }
        return null;
    }

    @Override
    public boolean saveOrUpdateConfig(Config config) {
        //通过key查询是否存在
        Config existOne = getOneByKey(config.getKey());
        if(existOne==null){
            return saveOne(config);
        }else {
            existOne.setValue(config.getValue());
            return updateOne(existOne);
        }
    }

    @Override
    public void setByKey(String key, Config config) {
        String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
        Assert.isTrue(ObjectUtils.isNotEmpty(tenantId), "租户Id为空");
        QueryWrapper<Config> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("key_", key);
        queryWrapper.eq("tenant_id", tenantId);
        List<Config> list = list(queryWrapper);
        if (list.isEmpty()) {
            // 新增
            // 设置枚举常量中的配置信息
            ConfigConstant model = ConfigConstant.getByKey(key);
            assert model != null;
            config.setKey(key);
            config.setTenantId(tenantId);
            config.setModuleLevel(model.getModuleLevel());
            config.setDescribe(model.getDescribe());
            Date date = Calendar.getInstance().getTime();
            config.setCreateTime(date);
            config.setModifyTime(date);
            Assert.isTrue(config.getValue() != null, "参数值不能为空");
            config.setExample(model.getExample());
            saveOne(config);
        } else {
            // key+tenantId 唯一 只能查到一个
            Config config2 = list.get(0);
//            removeById(config2.getId());
            // 删除后新增
            config2.setValue(config.getValue()).setModifyTime(new Date());
            updateById(config2);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(Config appConfig) {
        Assert.notNull(appConfig.getId(), "id不能为空");
        commonService.setModifyInfo(appConfig);
        appConfig.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validRepeat(appConfig);
        validParamFormat(appConfig);
        return updateById(appConfig);
    }

    @Override
    public IPage<Config> selectPage(Page page, Config config, boolean queryGlobal) {
        if (!queryGlobal) {
            config.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        }
        return baseMapper.selectList2(page, config);
    }

    @Override
    public List<Config> selectList(Config config, boolean queryGlobal) {
        if (!queryGlobal) {
            config.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        }
        return baseMapper.selectList2(config);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(List<Long> idList) {
        return removeByIds(idList);
    }

    @Override
    public void export(Config appConfig, HttpServletRequest request, HttpServletResponse
            response) {

        IPage<Config> page = selectPage(new Page(0, -1), appConfig,false);
        List<Config> records = page.getRecords();
        List
                <ConfigVo> appConfigVos = new ArrayList<>();
        for (Config expert : records) {
            appConfigVos.add(new ConfigVo(expert));
        }

        String keyValue = "关键字:key,租户id:tenantId";
        String title = "Config导出数据";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, appConfigVos, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }

    @Override
    public Config getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    /**
     * 校验重复
     */
    private void validRepeat(Config appConfig) {
        QueryWrapper<Config> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("key_", appConfig.getKey());
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<Config> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("关键字有重复");
        }
        if (ObjectUtils.isEmpty(appConfig.getId())) {
            throw new BusinessException("关键字已存在");
        }
        if (!appConfig.getId().equals(list.get(0).getId())) {
            throw new BusinessException("关键字已存在");
        }

    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(Config appConfig) {
        Assert.notNull(appConfig, "参数为空");
        Assert.isTrue(StringUtils.isNotBlank(appConfig.getKey()), "关键字为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(Config appConfig) {
        Assert.isTrue(appConfig.getKey() == null || appConfig.getKey().length() <= 100,
                "关键字超长");
    }

    @Value("${edu.url}")
    private String eduUrl;

    @Override
    public String getEduUrl() {
        return eduUrl;
    }
}

